package momo.multitree.algo;

import momo.multitree.structure.*;

import java.util.Collection;
import java.util.LinkedHashSet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class EdgesMstSptValidator implements AllTreeVisitor {
	
	private Log log = LogFactory.getLog(EdgesMstSptValidator.class);
	
	private Graph graph;
	
	private Collection<Tree> minCostTrees = new LinkedHashSet<Tree>();;
	
	private double minCost = Double.POSITIVE_INFINITY;
	
	public EdgesMstSptValidator(Graph graph) {
		this.graph = graph;
	}
	
	
	@Override
	public void visit(Tree t) {
		double currCost = t.compCost(false); 
		if ( currCost < minCost ) {
			minCost = currCost;
			minCostTrees.clear();
			minCostTrees.add(t);
		} else {
			if ( currCost == minCost ) {
				minCostTrees.add(t);
			}
		}
	}
	
	public boolean validateOnBestTree() {
		for (Tree tree : minCostTrees) {
			if (validateOnBestTree(tree, false))
				return true;
		}
		// no tree validates
		log.error("No tree validates; showing errors for each tree");
		for (Tree tree : minCostTrees) 
			validateOnBestTree(tree, true);
		return false;
	}
	
	public boolean validateOnBestTree(Tree minCostTree, boolean reportErrors) {
		Tree mstTree = new PrimMinSpanTree().mstCostTree(graph, minCostTree.getRoot());
		Tree sptTree = new CostShortestPath().optimumTree(graph, minCostTree.getRoot());
		
		for (Edge edge : minCostTree.getEdges()) {
			if ((!mstTree.getEdges().contains(edge)) && (!sptTree.getEdges().contains(edge))) {
				if (reportErrors) {
					log.error("edge: "+edge+" not in mst and spt");
					log.error("best tree: "+minCostTree);
					log.error("mst tree: "+mstTree);
					log.error("spt tree: "+sptTree);
				}
				return false;
			}
		}
		return true;

	}

}
